import {isReactive} from "./reactive.js";
import {ReactiveEffect} from "./effect.js";
import {isFunction, isObject} from "../shared/index.js";

function traverse(source, seen = new Set()) {
    if (!isObject(source)) {
        return source
    }
    // 对象循环引用，如果已经有了，直接返回
    if (seen.has(source)) {
        return source
    }
    seen.add(source)
    for (let k in source) {
        // 这里访问了对象中的所有属性，触发依赖收集
        traverse(source[k], seen)
    }
    return source
}

export function watch(source, cb, options) {
    doWatch(source, cb, options)
}

export function watchEffect(effect, options) {
    doWatch(effect, null, options)
}

function doWatch(source, cb, options) {
    let getter
    if (isReactive(source)) {
        // 要进行依赖收集
        getter = () => traverse(source)
    } else if (isFunction(source)) {
        getter = source
    }
    let oldValue
    let clean

    const onCleanup = (fn) => {
        clean = fn
    }
    const job = () => {
        if (cb) {
            if (clean) clean()
            const newValue = effect.run()
            cb(newValue, oldValue, onCleanup)
            oldValue = newValue
        } else {
            effect.run()
        }

    }
    const effect = new ReactiveEffect(getter, job)
    if (options && options.immediate) {
        job()
    }
    oldValue = effect.run()
}
